home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
pcmagazi
/
1988
/
02
/
paint.asm
< prev
next >
Wrap
Assembly Source File
|
1987-10-22
|
66KB
|
1,513 lines
include paint.pub
;PAINT.COM for the IBM Personal Computer - 1987 by Jeff Prosise
bios_data segment at 40h
org 1Ah
buffer_head dw ? ;pointer to keyboard buffer head
buffer_tail dw ? ;pointer to keyboard buffer tail
org 63h
addr_6845 dw ? ;CRT Controller address
org 80h
buffer_start dw ? ;starting keyboard buffer address
buffer_end dw ? ;ending keyboard buffer address
bios_data ends
code segment para public 'code'
assume cs:code
org 100h
begin: jmp main
copyright db 'PAINT 1.0 (c) 1987 Ziff Communications Co.',13,10
db 'PC Magazine ',254,' Jeff Prosise',13,10,'$',1Ah
errmsg1 db 13,10,'File not found',13,10,'$'
errmsg2 db 13,10,'Error reading file',13,10,'$'
errmsg3 db 13,10,'Not enough memory',13,10,'$'
kbcode db 10h ;get keystroke function code
fileptr dw 81h ;pointer to file name text
data_segment dw ? ;buffer segment
doscolor db ? ;screen color before execution
insert_flag db 0 ;0=overwrite, 1=insert
write_mode db 0 ;video insertion mode
bufferptr db 0 ;pointer to current buffer page
maxpage db 0 ;maximum page number
mode db 0 ;0=color, 1=monochrome
columns db ? ;number of display columns -1
lcolumns dw ? ;number of display columns
crtc_addr dw ? ;CRT Controller base address
blockxy dw 0FFFFh ;first corner of block
attribute db 1Fh ;current paint attribute
graphics db 0 ;current box character
defchar db ? ;default box character
boxid db ? ;box environment byte
maskval db 01010101b ;graphics mask value
menu_attr db 1Bh ;menu line attribute
video_segment dw 0B800h ;video buffer segment
delta dw ? ;line length variable
linelength dw ? ;line length in bytes
keyboard label dword
old9h dw 2 dup (?) ;old interrupt 9h vector
quit_text db 'Exit to DOS (Y/N)?',0
save_text db 'Save as: ',0
box_text db '1-',179,32,32,'2-',186,32,32,'3-',176,32,32,'4-',177,32,32
db '5-',178,32,32,'6-',219,32,32,'7-*',0
fore_text db 'Foreground: 0 1 2 3 4 5 6 7 8 9 '
db 'A B C D E F',0
back_text db 'Back',0
mono_text db '1-Normal 2-Reverse 3-Bold 4-Underline',0
block_text db '1-Clear 2-Paint',0
mode_text db '1-Text Only 2-Text and Attributes',0
help_text db 'F1-Help F2-Attribute F3-Line F4-Mode F5-Block '
db 'F6-Save F7-Quit',0
key_table db 81,73,65,64,63,62,61,60,59,160,157,155,152,145,116
db 115,141,83,82,79,71,80,77,75,72
gr_table db 17,81,145,98,96,144,162,34,160,130,66,129,80
db 5,69,84,21,68,85,25,38,10,40,138,168,42,136
db 170,137,70,152,100,6,9,24,36,102,153,65,20
box_table db 176,177,178,219,42
mono_table db 7,70h,0Fh,1
jump_table dw offset up ;cursor-up key
dw offset left ;cursor-left key
dw offset right ;cursor-right key
dw offset down ;cursor-down key
dw offset home ;HOME key
dw offset endkey ;END key
dw offset insert ;INS key
dw offset delete ;DEL key
dw offset up ;Ctrl-Up
dw offset left ;Ctrl-Left
dw offset right ;Ctrl-Right
dw offset down ;Ctrl-Down
dw offset BoxUp ;Alt-Up
dw offset BoxLeft ;Alt-Left
dw offset BoxRight ;Alt-Right
dw offset BoxDown ;Alt-Down
dw offset help ;F1
dw offset SelectAttr ;F2
dw offset SelectBox ;F3
dw offset SelectMode ;F4
dw offset block ;F5
dw offset save ;F6
dw offset quit ;F7
dw offset PgUp ;PgUp
dw offset PgDn ;PgDn
;-----------------------------------------------------------------------------
;KBINT handles interrupt 9 and generates new extended keycodes.
;-----------------------------------------------------------------------------
kbint proc near
sti ;interrupts on
push ax ;save AX and BX
push bx
in al,60h ;read scan code
cmp al,72 ;cursor up?
je checkctrl
cmp al,75 ;cursor left?
je checkctrl
cmp al,77 ;cursor right?
je checkctrl
cmp al,80 ;cursor down?
je checkctrl
oldint: pop bx ;restore AX and BX
pop ax
jmp keyboard ;exit to BIOS handler
;
;Generate extended codes for Ctrl-Up, Down.
;
checkctrl: mov bl,al ;save scan code in BL
mov ah,2 ;get shift key status
int 16h
test al,4 ;Ctrl key pressed?
jz checkalt ;no, then check Alt key
cmp bl,75 ;pass left or right key to BIOS
je oldint
cmp bl,77
je oldint
add bl,45h ;create new extended code
cmp bl,141
je process
mov bl,145
jmp short process ;process it
;
;Generate extended codes for Alt-Up, Down, Left, and Right.
;
checkalt: test al,8 ;Alt key pressed?
jz oldint ;no, then exit to BIOS
add bl,50h ;create new extended code
;
;Reset the keyboard and clear the interrupt.
;
process: in al,61h ;read control port value
mov ah,al ;save it in AH
or al,80h ;set the high bit
out 61h,al ;reset keyboard
mov al,ah ;retrieve original value
out 61h,al ;enable keyboard
cli
mov al,20h ;end the interrupt
out 20h,al
sti
;
;Insert the new keycode into the keyboard buffer.
;
mov ah,bl ;transfer code to AH
xor al,al ;zero AL
push dx ;save DX and DS
push ds
mov bx,bios_data ;point DS to BIOS data area
mov ds,bx
assume ds:bios_data
cli ;interrupts off
mov bx,buffer_tail ;get current tail address
mov dx,bx ;transfer it to DX
add dx,2 ;advance to next position
cmp dx,buffer_end ;wrap around if necessary
jne buffer
mov dx,buffer_start
buffer: cmp dx,buffer_head ;is the buffer full?
je kbexit ;yes, then exit now
mov [bx],ax ;insert keycode into buffer
mov buffer_tail,dx ;advance tail
kbexit: sti ;enable interrupts
pop ds ;restore registers
assume ds:nothing
pop dx
pop bx
pop ax
iret ;and exit
kbint endp
;-----------------------------------------------------------------------------
;MAIN is the main procedure.
;-----------------------------------------------------------------------------
main proc near
assume cs:code,ds:code,es:code
;
;Request 64K of memory for buffer space.
;
mov ah,4Ah ;release memory beyond code seg
mov bx,4096
int 21h
mov ah,48h ;request 4000 paragraphs
mov bx,4000
int 21h
jnc save_seg ;continue if request granted
mov dx,offset errmsg3 ;abort if request denied
jmp short error_exit
save_seg: mov data_segment,ax ;save data segment
;
;Parse the command line for a filename.
;
cld ;clear DF
mov si,81h ;point SI to command line
parse1: lodsb ;find first non-space
cmp al,32
je parse1
cmp al,13 ;end-of-line?
jne filefound ;no, then it's a filename
mov byte ptr ds:[81h],0 ;place delimiter for no file
jmp short exbios ;skip file load
filefound: dec si ;save starting text address
mov fileptr,si
mov bl,ds:[80h] ;zero last byte in string
xor bh,bh
mov byte ptr ds:[bx+81h],0
;
;Open the file designated on the command line for input.
;
mov ax,3D00h ;request read-only access
mov dx,si ;point DS:DX to filespec
int 21h
jnc read_file ;branch if open succeeded
mov dx,offset errmsg1 ;print 'File not found'
error_exit: mov ah,9
int 21h
mov ax,4C01h ;terminate with error code
int 21h
;
;Read character/attribute data from the file.
;
read_file: mov bx,ax ;transfer file handle to BX
mov ah,3Fh ;read file data
mov cx,64000 ;request 64,000 bytes
push ds ;point DS to data segment
mov ds,data_segment
assume ds:nothing
xor dx,dx ;point DX to beginning of segment
int 21h
pop ds ;restore DS
assume ds:code
jnc check_read ;branch if no error occurred
mov dx,offset errmsg2 ;abort on read error
jmp short error_exit
check_read: or ax,ax ;abort if no bytes read
jne paginate
mov dx,offset errmsg2
jmp short error_exit
paginate: dec ax ;decrement count by 1
xor dx,dx ;determine number of pages
mov bx,4000
div bx
mov maxpage,al ;save maximum page number
close_file: mov ah,3Eh ;close file
int 21h
;
;Determine whether or not the BIOS supports extended keyboard functions.
;
exbios: mov ah,5 ;write FFFFh to keyboard buffer
mov cx,0FFFFh
int 16h
mov ah,10h ;then read it back
int 16h
cmp ax,0FFFFh ;is AX set correctly?
je video ;yes, then don't reset INT 9
;
;Point the interrupt 9 vector to the internal keyboard handler.
;
mov kbcode,0 ;modify KBCODE for old BIOS
push es
assume es:nothing
mov ax,3509h ;get current vector
int 21h
mov old9h,bx ;save it
mov old9h[2],es
mov ax,2509h ;then reset it
mov dx,offset kbint
int 21h
pop es
assume es:code
;
;Determine whether video is color or monochrome.
;
video: push ds ;get address of CRT Controller
mov ax,bios_data
mov ds,ax
assume ds:bios_data
mov ax,addr_6845
mov crtc_addr,ax ;save it
pop ds
assume ds:code
test ax,40h ;is bit 6 of CRTC address set?
jnz more_video ;yes, then it's a color adapter
inc mode ;no, then it's monochrome
mov video_segment,0B000h ;modify attributes for monochrome
mov attribute,7
mov menu_attr,7
;
;Determine number of display columns, screen color, and video page number.
;
more_video: mov ah,15 ;get number of columns and page
int 10h
mov al,ah
xor ah,ah
mov lcolumns,ax ;store number of columns
mov linelength,ax ;store line length in bytes
shl linelength,1
dec al ;store number of columns - 1
mov columns,al
mov cl,79 ;determine number of bytes
sub cl,al ; from end of one line to
shl cl,1 ; beginning of next
xor ch,ch
mov delta,cx
cmp al,79 ;adjust if more than 80 columns
jna no_adjust ; are currently displayed
mov columns,79
mov lcolumns,80
mov delta,0
no_adjust: mov ah,8 ;read current attribute
int 10h
mov doscolor,ah ;store it for use upon exit
or bh,bh ;make sure page zero is active
je clrscr
mov ax,0500h ;activate it if it's not
int 10h
;
;Clear the screen or write data read from screen file to video memory.
;
clrscr: cmp byte ptr ds:[81h],0 ;was a data file read?
jne show_file ;yes, then display contents
mov bh,attribute ;no, then clear the screen
call ClearScreen
jmp short getkey ;leave starting screen blank
show_file: call ShowFile
;
;Solicit keystrokes and process non-extended keycodes.
;
getkey: call ReadKey ;get a keystroke
or al,al ;branch on entry of extended code
je excode
cmp al,0E0h
je excode
cmp al,8 ;BACKSPACE key?
jne enter
or dl,dl ;currently at left edge of screen?
je getkey ;yes, then ignore it
call backspace ;delete last character
jmp short getkey ;return for more
enter: cmp al,13 ;ENTER key?
jne escape
mov ah,2 ;advance cursor to next line
xor bh,bh
inc dh
cmp dh,25 ;wrap around if necessary
jne nowrap
xor dh,dh
nowrap: xor dl,dl
int 10h
jmp short getkey ;return for more
escape: cmp al,27 ;ESC key?
jne charkey
mov blockxy,0FFFFh ;reset block indicator
jmp short getkey ;return for more
charkey: cmp al,32 ;character key?
jb getkey ;no, then ignore it
call WriteChar ;yes, then process it
jmp short getkey ;return for more
;
;Process an extended keycode.
;
excode: mov al,ah ;transfer keycode to AL
mov di,offset key_table ;point DI to keycode table
mov cx,25 ;25 keycodes to check
repne scasb ;scan table for current keycode
jne getkey ;return if keycode not found
mov bx,cx ;move index to BX
pcall: shl bx,1 ;double it
call cs:[offset jump_table+bx] ;call handling routine
mov ah,3 ;get cursor position
xor bh,bh
int 10h
jmp short getkey ;return for more
main endp
;-----------------------------------------------------------------------------
;ShowFile displays a 4000-byte block indexed by DATA_SEGMENT and BUFFERPTR.
;-----------------------------------------------------------------------------
ShowFile proc near
mov ax,4000 ;find starting buffer address
mov bl,bufferptr
xor bh,bh
mul bx
mov si,ax ;transfer it to SI
push ds ;point DS to data segment
assume ds:nothing
mov ds,data_segment
xor dx,dx ;set DX for home cursor position
mov cx,25 ;25 display lines
show1: push cx
mov cx,lcolumns ;number of display columns
show2: push cx
mov ah,2 ;position the cursor
int 10h
lodsw ;get one C/A pair
mov bl,ah ;transfer attribute to BL
mov ah,9 ;display character and attribute
mov cx,1
int 10h
inc dl ;advance cursor
pop cx
loop show2 ;loop until this line is done
inc dh ;home cursor to start of next line
xor dl,dl
add si,delta ;adjust SI for other than 80 cols
pop cx
loop show1 ;loop until 25 lines are done
pop ds ;restore DS
assume ds:code
mov ah,2 ;home the cursor
xor dx,dx
int 10h
ret ;and exit
ShowFile endp
;-----------------------------------------------------------------------------
;ReadKey reads a keypress.
;Exit: AX - keycode
;-----------------------------------------------------------------------------
ReadKey proc near
mov ah,kbcode ;get function code
inc ah
int 16h ;check buffer status
jnz read ;branch if a keycode is ready
int 28h ;generate interrupt 28h
jmp short ReadKey ;enter polling loop again
read: mov ah,kbcode ;read key
int 16h
ret ;and exit
ReadKey endp
;-----------------------------------------------------------------------------
;ClearScreen clears the 25-line viewing area and homes the cursor.
;Entry: BH - attribute
;-----------------------------------------------------------------------------
ClearScreen proc near
mov ax,0600h ;clear screen with function 6
xor cx,cx
mov dh,24
mov dl,columns
int 10h
mov ah,2 ;home the cursor
xor dx,dx
xor bh,bh
int 10h
ret
ClearScreen endp
;-----------------------------------------------------------------------------
;HELP presents a help line denoting function key assignments.
;-----------------------------------------------------------------------------
help proc near
mov si,offset help_text ;display help text
call MenuLine
help1: call readkey ;wait for a keypress
call RestoreLine ;erase the help line
ret
help endp
;-----------------------------------------------------------------------------
;QUIT exits the application.
;-----------------------------------------------------------------------------
quit proc near
mov si,offset quit_text ;display menu line
call MenuLine
quit1: call ReadKey ;get a keypress
and al,0DFh ;capitalize response
cmp al,'Y' ;was the response 'Yes?'
je quit2 ;yes, then exit
cmp al,'N' ;was the response 'No?'
je quit4 ;yes, then return to application
cmp al,27 ;ESC key?
je quit4 ;yes, then return to application
jmp short quit1 ;get another keypress
quit2: mov bh,doscolor ;clear screen before exit
call ClearScreen
mov ah,1 ;restore the cursor
mov cx,cursor_mode
int 10h
cmp kbcode,10h ;skip ahead if extended BIOS
je quit3
xor ax,ax ;restore the interrupt 9 vector
mov es,ax
cli
mov ax,old9h
mov es:[24h],ax
mov ax,old9h[2]
mov es:[26h],ax
sti
quit3: add sp,4 ;clean up the stack
mov ah,9
mov dx,offset copyright
int 21h
mov ax,4C00h ;terminate
int 21h
quit4: call RestoreLine ;restore menu line
ret ;return to application
quit endp
;-----------------------------------------------------------------------------
;SAVE saves the current screen to disk.
;-----------------------------------------------------------------------------
save proc near
mov si,offset save_text ;display menu line
call MenuLine
mov ah,1 ;display cursor
mov cx,cursor_mode
int 10h
getname: mov si,fileptr ;read filespec from keyboard
mov di,si
mov cl,70
mov dx,1809h
call ReadString
or cl,cl ;stop if nothing was entered
jne save_file
call RestoreLine
ret
save_file: mov ah,3Ch ;open the file for writing
xor cx,cx
mov dx,fileptr
int 21h
jc save_error ;jump on error
push ax ;save file handle
call RestoreLine ;restore menu line
mov ah,3 ;read and save cursor position
xor bh,bh
int 10h
push dx
call PutVideo ;copy video to data buffer
mov ah,2 ;reset cursor
pop dx
int 10h
mov ax,4000 ;write data to disk
mov bl,maxpage
inc bl
xor bh,bh
mul bx
mov cx,ax
mov ah,40h
pop bx
push ds
mov ds,data_segment
assume ds:nothing
xor dx,dx
int 21h
pop ds
assume ds:code
mov ah,3Eh ;close the file
int 21h
ret
;
;An error was encountered opening the file. Resolicit the filespec.
;
save_error: mov ax,0E07h ;beep
int 10h
mov ah,2 ;reset cursor
mov dx,1809h
xor bh,bh
int 10h
jmp getname ;solicit filespec again
save endp
;-----------------------------------------------------------------------------
;PutVideo writes the current video page to the data buffer.
;-----------------------------------------------------------------------------
PutVideo proc near
push es ;point ES:DI to buffer
mov es,data_segment
assume es:nothing
mov ax,4000
mov bl,bufferptr
xor bh,bh
mul bx
mov di,ax
xor dx,dx
mov cx,25 ;copy contents a line at a time
put2: push cx
mov cx,lcolumns
put3: mov ah,2
int 10h
mov ah,8
int 10h
stosw
inc dl
loop put3
add di,delta ;adjust for other than 80 columns
inc dh
xor dl,dl
pop cx
loop put2
pop es ;restore ES and exit
assume es:code
ret
PutVideo endp
;-----------------------------------------------------------------------------
;BLOCK function allows screen regions to be cleared or painted.
;-----------------------------------------------------------------------------
bwidth db ? ;block width in columns
firstcol db ? ;starting column number of block
c_loc dw ? ;cursor position
block proc near
cmp blockxy,0FFFFh ;first corner?
jne block1 ;no, then branch
mov blockxy,dx ;yes, then save cursor position
ret ;and exit
block1: mov cx,blockxy ;retrieve opposite corner location
cmp cx,dx ;are CX and DX the same?
jne notfull ;no, then branch
xor cx,cx ;yes, then indicate full screen
mov dh,24
mov dl,columns
jmp short block3
notfull: cmp cl,dl ;swap if necessary
jbe block2
xchg cl,dl
block2: cmp ch,dh
jbe block3
xchg ch,dh
block3: push cx ;save block parameters
push dx
mov si,offset block_text ;display menu line
call MenuLine
;
;Block corners are recorded. Get menu option and act accordingly.
;
block4: call ReadKey ;get response
cmp al,27 ;ESC key?
jne block5
mov blockxy,0FFFFh ;reset block definition
call RestoreLine ;restore menu line
pop dx ;clean up the stack and exit
pop cx
ret
;
;Clear the indicated region if menu option '1' was selected.
;
block5: cmp al,'1' ;clear region?
jne block6
call RestoreLine ;restore last line
pop dx ;retrieve block corrdinates
pop cx
mov ax,0600h ;yes, then clear contents
mov bh,attribute
int 10h
mov blockxy,0FFFFh ;reset block function
ret
;
;Paint the indicated region if menu option '2' was selected.
;
block6: cmp al,'2' ;paint region?
jne block4
call RestoreLine ;restore menu line
mov ah,3 ;get cursor position
xor bh,bh
int 10h
mov c_loc,dx ;save it
pop cx ;retrieve and swap parameters
pop dx
mov firstcol,dl ;save starting column number
sub cl,dl ;determine block width
inc cl
mov bwidth,cl
sub ch,dh ;then block height
inc ch
mov cl,ch
xor ch,ch
block7: push cx ;scan region and set attributes
mov cl,bwidth
xor ch,ch
block8: push cx
mov ah,2 ;position cursor
int 10h
call SetAttribute ;set current attribute
inc dl ;advance to next column
pop cx
loop block8 ;loop until this line is complete
inc dh ;advance to next row
mov dl,firstcol
pop cx
loop block7 ;loop until all lines are done
mov ah,2 ;restore cursor position
mov dx,c_loc
int 10h
mov blockxy,0FFFFh ;reset block function
ret
block endp
;-----------------------------------------------------------------------------
;Box routines process presses of Alt-Up, Down, Right, and Left.
;-----------------------------------------------------------------------------
BoxUp proc near
or dh,dh ;top line?
je boxup1 ;yes, then ignore keypress
mov al,7 ;generate default code
mul graphics
add al,179
mov bx,dx ;define next cursor location
dec bh
mov boxid,16 ;bias box code
call DrawChars ;draw box characters
boxup1: ret
BoxUp endp
BoxDown proc near
cmp dh,24 ;bottom line?
je boxdn1 ;yes, then ignore keypress
mov al,7 ;generate default code
mul graphics
add al,179
mov bx,dx ;define next cursor location
inc bh
mov boxid,1 ;bias box code
call DrawChars ;draw box characters
boxdn1: ret
BoxDown endp
BoxLeft proc near
or dl,dl ;left edge of screen?
je boxlf1 ;yes, then ignore keypress
mov al,9 ;generate default code
mul graphics
add al,196
mov bx,dx ;define next cursor location
dec bl
mov boxid,4 ;bias box code
call DrawChars ;draw box characters
boxlf1: ret
BoxLeft endp
BoxRight proc near
cmp dl,columns ;right edge of screen?
je boxrt1 ;yes, then ignore keypress
mov al,9 ;generate default code
mul graphics
add al,196
mov bx,dx ;define next cursor location
inc bl
mov boxid,64 ;bias box code
call DrawChars ;draw box characters
boxrt1: ret
BoxRight endp
;-----------------------------------------------------------------------------
;DrawChars is called by the directional box routines to draw box characters.
;Entry: AL - default box character
; BX - next cursor position
;-----------------------------------------------------------------------------
DrawChars proc near
mov defchar,al ;store default code
push bx ;save next cursor location
cmp graphics,0 ;adjust BOXID if double line
je drawc1
shl boxid,1
drawc1: call DrawBox ;draw character in current cell
mov ah,2 ;move cursor
pop dx
xor bh,bh
int 10h
mov boxid,0 ;reset box code
call DrawBox ;draw next box character
ret
DrawChars endp
;-----------------------------------------------------------------------------
;DrawBox draws the appropriate box character at the current cursor position.
;-----------------------------------------------------------------------------
DrawBox proc near
cmp graphics,1 ;branch if line drawing characters
jna db1 ; are selected
mov al,graphics ;form character code
sub al,2
mov bx,offset box_table
xlat box_table
jmp short db3 ;display character and exit
db1: call GetEnv ;determine character code
mov al,boxid ;transfer to AL
mov cl,4 ;generate desired character code
rol al,cl
mov cx,40 ;see if character exists
mov di,offset gr_table
repne scasb
je db2 ;display it if it does
and al,maskval ;mask mixed characters
mov cx,40 ;search again
mov di,offset gr_table
repne scasb
je db2
mov al,defchar ;default to line character
jmp short db3
db2: mov al,218 ;print the character
sub al,cl
db3: call DisplayChar
ret
DrawBox endp
;-----------------------------------------------------------------------------
;SelectMode lets the user specify whether attributes will be inserted
;along with typed text.
;-----------------------------------------------------------------------------
SelectMode proc near
mov si,offset mode_text ;display menu line
call MenuLine
sm1: call ReadKey ;get response
cmp al,27 ;check for ESC key
je sm2
cmp al,'1' ;reject invalid entries
jb sm1
cmp al,'2'
ja sm1
sub al,'1' ;normalize entry
mov write_mode,al ;save it
sm2: call Restoreline ;close and exit
ret
SelectMode endp
;-----------------------------------------------------------------------------
;SelectBox pops up the box character selection menu.
;-----------------------------------------------------------------------------
SelectBox proc near
mov si,offset box_text ;display menu line
call MenuLine
sb1: call ReadKey ;get response
cmp al,27 ;ESC key?
je sb3 ;yes, then exit
cmp al,13 ;ENTER?
je sb3 ;yes, then exit
cmp al,'1' ;reject invalid responses
jb sb1
cmp al,'7'
ja sb1
sub al,'1' ;normalize entry
mov graphics,al ;then store it
or al,al ;set mask value
jne sb2
mov maskval,01010101b
jmp short sb3
sb2: cmp al,1
jne sb3
mov maskval,10101010b
sb3: call RestoreLine ;restore menu line
ret
SelectBox endp
;-----------------------------------------------------------------------------
;SelectAttr pops up the screen attribute selection menu.
;-----------------------------------------------------------------------------
tmpcol db ? ;attribute under cursor
SelectAttr proc near
mov ah,8 ;get attribute under cursor
xor bh,bh
int 10h
mov tmpcol,ah ;save it
cmp mode,0 ;color video?
je sa0 ;yes, then branch
;
;Display attribute menu for monochrome systems.
;
mov si,offset mono_text ;display menu line
call MenuLine
mono1: call ReadKey ;get response
or al,al ;function key F2?
jne mono2
cmp ah,60
jne mono1
mov ah,tmpcol ;use attribute under cursor
mov attribute,ah
jmp short mono3 ;exit
mono2: cmp al,27 ;exit if ESC was pressed
je mono3
cmp al,'1' ;reject invalid responses
jb mono1
cmp al,'4'
ja mono1
sub al,'1' ;normalize entry
mov bx,offset mono_table ;determine new attribute
xlat mono_table
mov attribute,al ;save it
mono3: call RestoreLine ;restore line and exit
ret
;
;Display attribute menu for color systems.
;
sa0: mov si,offset fore_text ;display menu line
call MenuLine
mov dx,180Eh ;display colors
xor bx,bx
sa1: mov ah,2
int 10h
mov ax,09DBh
mov cx,2
int 10h
add dl,4
inc bl
test bl,10h
jz sa1
sa2: call ReadKey ;get foreground color response
or al,al ;function key F2?
jne notf1
cmp ah,60
jne sa2
mov ah,tmpcol ;use attribute under cursor
mov attribute,ah
jmp short endselect ;and exit
notf1: cmp al,13 ;ENTER key?
je sa4
cmp al,27 ;ESC?
je endselect
cmp al,'0' ;reject invalid responses
jb sa2
cmp al,'9'
jna sa3
and al,0DFh ;normalize entry
cmp al,'A'
jb sa2
cmp al,'F'
ja sa2
sub al,7
sa3: sub al,30h
and attribute,0F0h ;modify foreground color
or attribute,al
sa4: mov si,offset back_text ;display background colors
mov dx,1800h
mov bl,menu_attr
call WriteLine
mov ah,2
mov dx,182Ch
int 10h
mov ax,0920h
mov cx,34
int 10h
sa5: call ReadKey ;get background color response
cmp al,13
je endselect
cmp al,27
je endselect
cmp al,'0'
jb sa4
cmp al,'7'
ja sa4
sub al,30h
mov cl,4
shl al,cl
and attribute,0Fh ;modify background color
or attribute,al
endselect: call RestoreLine ;restore menu line
ret
SelectAttr endp
;-----------------------------------------------------------------------------
;WriteChar processes a press of a character key.
;-----------------------------------------------------------------------------
WriteChar proc near
cmp insert_flag,0 ;insert state on?
je disp_char ;no, then skip insert sequence
mov cl,columns ;calculate number of shifts
sub cl,dl
xor ch,ch
jcxz disp_char
push ax ;save character and position
push dx
call VideoAddr ;calculate video address
mov bx,cx ;determine starting address
shl bx,1
add si,bx
mov di,si
sub si,2
push ds ;save DS and ES
push es
assume ds:nothing,es:nothing
mov ds,video_segment
mov es,video_segment
std ;set DF temporarily
mov dx,crtc_addr ;get CRT Controller address
add dx,6 ;address status register
vwait: in al,dx ;wait for vertical retrace
test al,8
jz vwait
cmp write_mode,0 ;push text and attributes?
jne push_all ;yes, then branch
write_loop: movsb ;shift text only
dec si
dec di
loop write_loop
jmp short shift_done
push_all: rep movsw ;shift text and attributes
shift_done: cld ;restore DF
pop es ;restore DS and ES
pop ds
assume ds:code,es:code
pop dx ;retrieve character and position
pop ax
disp_char: call DisplayChar ;display the character
mov ah,2 ;advance the cursor
cmp dl,columns ;prevent overrun
je nomove
inc dl
nomove: int 10h
ret
WriteChar endp
;-----------------------------------------------------------------------------
;VideoAddr calculates the page zero video buffer address that corresponds
;to the cursor coordinates held in DX.
;Entry: DH,DL - cursor row and column | Exit: SI - buffer offset
;-----------------------------------------------------------------------------
VideoAddr proc near
mov ax,linelength ;row * 160
mul dh
shl dl,1 ;add column * 2
xor dh,dh
add ax,dx
mov si,ax ;transfer to SI
ret
VideoAddr endp
;-----------------------------------------------------------------------------
;INSERT processes a press of the INS key.
;-----------------------------------------------------------------------------
insert proc near
xor insert_flag,1 ;toggle flag
ret
insert endp
;-----------------------------------------------------------------------------
;UP processes a press of Cursor-Up or Ctrl-Up.
;-----------------------------------------------------------------------------
up proc near
or dh,dh ;currently on top row?
je done ;yes, then ignore the keypress
push ax ;save keycode
cmp al,100 ;paint cell if Ctrl is pressed
jb up1
call SetAttribute
up1: dec dh ;move cursor up a row
set_cursor: mov ah,2
xor bh,bh
int 10h
pop ax ;retrieve keycode
cmp al,100 ;paint cell if Ctrl is pressed
jb done
call SetAttribute
done: ret
up endp
;-----------------------------------------------------------------------------
;LEFT processes a press of Cursor-Left or Ctrl-Left.
;-----------------------------------------------------------------------------
left proc near
or dl,dl ;currently at left edge?
je done ;yes, then ignore the keypress
push ax ;save keycode
cmp al,100 ;paint cell if Ctrl is pressed
jb lf1
call SetAttribute
lf1: dec dl ;move cursor left one column
jmp short set_cursor
left endp
;-----------------------------------------------------------------------------
;RIGHT processes a press of Cursor-Right or Ctrl-Right.
;-----------------------------------------------------------------------------
right proc near
cmp dl,columns ;currently at right border?
je done ;yes, then ignore the keypress
push ax ;save keycode
cmp al,100 ;paint cell if Ctrl is pressed
jb rt1
call SetAttribute
rt1: inc dl ;move cursor right one column
jmp short set_cursor
right endp
;-----------------------------------------------------------------------------
;DOWN processes a press of Cursor-Down or Ctrl-Down.
;-----------------------------------------------------------------------------
down proc near
cmp dh,24 ;currently on bottom row?
je done ;yes, then ignore the keypress
push ax ;save keycode
cmp al,100 ;paint cell if Ctrl is pressed
jb dn1
call SetAttribute
dn1: inc dh ;move cursor down a row
jmp short set_cursor
down endp
;-----------------------------------------------------------------------------
;HOME processes a press of the HOME key.
;-----------------------------------------------------------------------------
home proc near
xor dl,dl ;set cursor to start of line
home1: mov ah,2
xor bh,bh
int 10h
ret
home endp
;-----------------------------------------------------------------------------
;ENDKEY processes a press of the END key.
;-----------------------------------------------------------------------------
endkey proc near
mov dl,columns ;set cursor to end of line
jmp home1
endkey endp
;-----------------------------------------------------------------------------
;PgUp and PgDn routines flip to the last/next page in the buffer.
;-----------------------------------------------------------------------------
PgUp proc near
cmp maxpage,0 ;ignore if there's only one page
je nopress
call PutVideo ;write current page to buffer
dec bufferptr ;go back one page
test bufferptr,80h ;wrap around if necessary
jz pg1
mov al,maxpage
mov bufferptr,al
pg1: call ShowFile ;display new page
nopress: ret ;exit
PgUp endp
PgDn proc near
cmp maxpage,0 ;ignore if there's only one page
je nopress
call PutVideo
inc bufferptr ;advance page pointer
mov al,maxpage ;wrap if necessary
cmp al,bufferptr
jae pg1
mov bufferptr,0
jmp short pg1
PgDn endp
;-----------------------------------------------------------------------------
;DisplayChar writes the character in AL to the current cursor position.
;-----------------------------------------------------------------------------
DisplayChar proc near
mov ah,9
cmp write_mode,0 ;write attribute also?
jne dc1
inc ah ;no, then change function number
dc1: xor bh,bh
mov bl,attribute
mov cx,1
int 10h
ret
DisplayChar endp
;-----------------------------------------------------------------------------
;SetAttribute sets the attribute of the character under the cursor.
;-----------------------------------------------------------------------------
SetAttribute proc near
mov ah,8 ;get character
xor bh,bh
int 10h
mov ah,9 ;write character and attribute
mov bl,attribute
mov cx,1
int 10h
ret
SetAttribute endp
;-----------------------------------------------------------------------------
;SaveLine saves the contents of the menu line.
;-----------------------------------------------------------------------------
cursor_mode dw ? ;cursor mode
cursor_pos dw ? ;cursor position
SaveLine proc near
mov ah,3 ;get cursor position and shape
xor bh,bh
int 10h
mov cursor_mode,cx ;save cursor parameters
mov cursor_pos,dx
mov ah,1 ;hide the cursor
mov ch,20h
int 10h
mov dx,1800h ;set starting cursor position
mov di,offset data_buffer ;point DI to save buffer
mov cx,lcolumns
sr1: mov ah,2 ;position the cursor
int 10h
mov ah,8 ;read character and attribute
int 10h
stosw ;store them
inc dl ;advance cursor to next column
loop sr1 ;loop until line is done
ret
SaveLine endp
;-----------------------------------------------------------------------------
;RestoreLine restores the contents of the previously saved menu line.
;-----------------------------------------------------------------------------
RestoreLine proc near
mov ah,1 ;hide the cursor
mov ch,20h
int 10h
xor bh,bh
mov si,offset data_buffer ;point SI to saved char/attr's
mov cx,lcolumns
mov dx,1800h ;initialize cursor position
rr1: push cx
mov ah,2 ;position the cursor
int 10h
lodsw ;get character and attribute
mov bl,ah ;transfer attribute to BL
mov ah,9 ;write character and attribute
mov cx,1
int 10h
inc dl ;advance cursor to next column
pop cx
loop rr1 ;loop until line is done
mov ah,2 ;restore cursor position and shape
mov dx,cursor_pos
int 10h
mov ah,1
mov cx,cursor_mode
int 10h
ret
RestoreLine endp
;-----------------------------------------------------------------------------
;GetEnv returns a value reflecting what lies on all four sides of the cursor.
;Entry: DH,DL - cursor position | Exit: BOXID - neighbor code
;-----------------------------------------------------------------------------
c_pos label word
c_col db ? ;cursor column
c_row db ? ;cursor row
GetEnv proc near
mov c_pos,dx ;save cursor position
call VideoAddr ;calculate video address
mov dx,crtc_addr
add dx,6
push ds ;save DS
mov ds,video_segment ;point DS to video buffer
assume ds:nothing
;
;Determine if what lies on the left affects the current cell.
;
sub si,2 ;address cell on left
cmp c_col,0 ;at left edge of screen?
je check2 ;yes, then skip test
test boxid,12 ;branch if BOXID is biased
jnz check2
mov ah,4
call MakeCode ;generate BOXID code
;
;Then do the same for the right side.
;
check2: add si,4
mov al,columns
cmp c_col,al
je check4
test boxid,192
jnz check4
mov ah,64
call MakeCode
;
;Check the character above the current cell.
;
check4: sub si,linelength
sub si,2
cmp c_row,0
je check6
test boxid,48
jnz check6
mov ah,16
call MakeCode
;
;Finish up by checking the character below.
;
check6: add si,linelength
add si,linelength
cmp c_row,24
je check8
test boxid,3
jnz check8
mov ah,1
call MakeCode
check8: pop ds ;restore DS
assume ds:code
mov dx,c_pos ;restore DX
ret ;and exit
GetEnv endp
;-----------------------------------------------------------------------------
;MakeCode modifies BOXID to reflect the character addressed by DS:SI.
;Entry: DS:SI - character
; AH - test value
; DX - video status register
;-----------------------------------------------------------------------------
MakeCode proc near
assume ds:nothing
call GetChar ;retrieve character
cmp al,179 ;exit if not a graphics character
jb make_exit
cmp al,218
ja make_exit
sub al,179 ;check for single extension
mov bx,offset gr_table
xlat gr_table
test al,ah
jz make1
or boxid,ah
jmp short make_exit
make1: shl ah,1 ;check for double extension
test al,ah
jz make_exit
or boxid,ah
make_exit: ret
MakeCode endp
;-----------------------------------------------------------------------------
;GetChar returns the character addressed by DS:SI in AL.
;Entry: DS:SI - character cell | Exit: AL - character code
; DX - video status register |
;-----------------------------------------------------------------------------
GetChar proc near
assume ds:nothing
in al,dx ;wait for horizontal scan
test al,1
jnz GetChar
cli ;interrupts off
wait1: in al,dx ;wait for next retrace
test al,1
jz wait1
mov al,[si] ;get the character
sti ;interrupts on
ret
GetChar endp
assume ds:code
;-----------------------------------------------------------------------------
;MenuLine opens a menu line at the bottom of the screen.
;Entry: DS:SI - text of menu line
;-----------------------------------------------------------------------------
MenuLine proc near
push si ;save string address
call SaveLine ;save current line contents
mov ah,2 ;position cursor on menu line
xor bh,bh
mov dx,1800h
int 10h
mov ax,0920h ;clear menu line
mov bl,menu_attr
mov cx,lcolumns
int 10h
pop si ;retrieve string address
call WriteLine ;display text
ret
MenuLine endp
;-----------------------------------------------------------------------------
;WriteLine displays a line of ASCIIZ text.
;Entry: DS:SI - text string
; DH,DL - cursor row and column
;-----------------------------------------------------------------------------
WriteLine proc near
mov ah,2 ;position the cursor
xor bh,bh
int 10h
write1: lodsb ;get a character
or al,al ;exit if it's zero
je write2
mov ah,10 ;write it
mov cx,1
int 10h
mov ah,2
inc dl
int 10h
jmp write1 ;loop back for more
write2: ret
WriteLine endp
;-----------------------------------------------------------------------------
;ReadString reads a string of text from the keyboard.
;Entry: CL - maximum length
; DH,DL - cursor position
; DS:SI - default string
; ES:DI - input buffer
;-----------------------------------------------------------------------------
maxlen db ? ;maximum accepted length
ReadString proc near
mov maxlen,cl ;store max length
xor cl,cl ;initialize counter
xor bh,bh
rs1: lodsb ;input default string
or al,al ;end of string?
je rs2 ;yes, then exit loop
inc di ;advance buffer pointer
inc cl ;increment count
mov ah,14 ;print the character
int 10h
jmp short rs1 ;loop until zero byte is reached
rs2: call ReadKey ;read the keyboard
cmp al,8 ;BACKSPACE key?
jne rs3
or cl,cl ;at beginning of line?
je rs2 ;yes, then ignore it
mov ah,14 ;move cursor back one space
int 10h
push cx ;delete the last character
mov ax,0A20h
mov cx,1
int 10h
pop cx
dec cl ;decrement count and pointer
dec di
jmp short rs2 ;return for more
rs3: cmp al,13 ;ENTER key?
jne rs4 ;no, then branch
xor al,al ;mark end of string
stosb
ret ;done
rs4: cmp al,27 ;ESC key?
jne rs5 ;no, then branch
xor cl,cl ;zero count
mov al,cl ;place delimiter
stosb
ret
rs5: cmp al,32 ;ASCII code less than 32?
jb rs2 ;yes, then ignore it
cmp cl,maxlen ;room for more?
je rs2 ;no, then ignore keypress
stosb ;buffer the character
inc cl ;increment count
mov ah,14 ;print the character
int 10h
jmp short rs2 ;return for more
ReadString endp
;-----------------------------------------------------------------------------
;BACKSPACE backspaces over the last character.
;Entry: DH,DL - cursor row and column
;-----------------------------------------------------------------------------
backspace proc near
mov ah,2 ;move cursor back one column
dec dl
xor bh,bh
int 10h
cmp insert_flag,0 ;is insert mode active?
je bs_exit ;no, then we're done
push dx ;save cursor position
call delete ;draw in everything to the right
pop dx ;retrieve position
bs_exit: ret
backspace endp
;-----------------------------------------------------------------------------
;DELETE shifts everything right of the cursor one cell left.
;Entry: DH,DL - cursor row and column
;-----------------------------------------------------------------------------
delete proc near
mov cl,columns ;calculate number of shifts
sub cl,dl
xor ch,ch
jcxz nodelete ;branch if there are none
call VideoAddr ;calculate video address
mov di,si
add si,2
push ds ;save DS and ES
push es
assume ds:nothing,es:nothing
mov ds,video_segment
mov es,video_segment
mov dx,crtc_addr ;get CRT Controller address
add dx,6 ;address status register
rwait: in al,dx ;wait for vertical retrace
test al,8
jz rwait
cmp write_mode,0 ;delete text and attribute?
jne delete_all ;yes, then branch
del_loop: movsb ;delete text only
inc si
inc di
loop del_loop
jmp short finish
delete_all: rep movsw ;shift characters and attributes
finish: mov byte ptr es:[di],32 ;blank final cell
pop es ;restore DS and ES
pop ds
assume ds:code,es:code
ret
nodelete: mov ax,0A20h ;blank character under cursor
xor bh,bh
mov cx,1
int 10h
ret
delete endp
data_buffer label byte ;buffer for menu line
code ends
end begin